package org.example.config;

import com.baomidou.mybatisplus.autoconfigure.SpringBootVFS;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.session.SqlSessionFactory;
import org.example.util.ExceptionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;
import java.io.IOException;
import java.util.Optional;
import java.util.stream.Stream;

public class DefaultSqlSessionFactory {

    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultSqlSessionFactory.class);
    private static final ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();

    private String mybatisConfigLocation;
    private String typeAliasesPackage;
    private String typeHandlersPackage;
    private String mapperLocations;

    public SqlSessionFactory getSessionFactory(@Qualifier("dataSource") DataSource dataSource, @Qualifier("databaseIdProvider") DatabaseIdProvider databaseIdProvider) throws Exception {
        MybatisSqlSessionFactoryBean sessionFactoryBean = new MybatisSqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);
        sessionFactoryBean.setVfs(SpringBootVFS.class);

        if (StringUtils.hasLength(this.getTypeAliasesPackage())) {
            sessionFactoryBean.setTypeAliasesPackage(this.getTypeAliasesPackage());
        } else {
            ExceptionUtil.throwRuntimeException("mybatis plus config : TypeAliasesPackage is null");
        }

        if (StringUtils.hasLength(this.getTypeHandlersPackage())) {
            sessionFactoryBean.setTypeHandlersPackage(this.getTypeHandlersPackage());
        }

        if (StringUtils.hasLength(this.getMapperLocations())) {
            String[] mapperLocationArr = this.getMapperLocations().split(",");
            Resource[] array = resolveMapperLocations(mapperLocationArr);
            sessionFactoryBean.setMapperLocations(array);
        } else {
            ExceptionUtil.throwRuntimeException("mybatis plus config : MapperLocations is null");
        }

        if (StringUtils.hasLength(this.getMybatisConfigLocation())) {
            sessionFactoryBean.setConfigLocation(resourceResolver.getResource(this.getMybatisConfigLocation()));
        }

        sessionFactoryBean.setDatabaseIdProvider(databaseIdProvider);
        return sessionFactoryBean.getObject();
    }

    public Resource[] resolveMapperLocations(String[] mapperLocationArr) {
        return Stream.of(Optional.ofNullable(mapperLocationArr).orElse(new String[0]))
                .flatMap(location -> Stream.of(getResources(location))).toArray(Resource[]::new);
    }

    private Resource[] getResources(String location) {
        try {
            return resourceResolver.getResources(location);
        } catch (IOException e) {
            return new Resource[0];
        }
    }

    public String getMybatisConfigLocation() {
        return mybatisConfigLocation;
    }

    public void setMybatisConfigLocation(String mybatisConfigLocation) {
        this.mybatisConfigLocation = mybatisConfigLocation;
    }

    public String getTypeAliasesPackage() {
        return typeAliasesPackage;
    }

    public void setTypeAliasesPackage(String typeAliasesPackage) {
        this.typeAliasesPackage = typeAliasesPackage;
    }

    public String getTypeHandlersPackage() {
        return typeHandlersPackage;
    }

    public void setTypeHandlersPackage(String typeHandlersPackage) {
        this.typeHandlersPackage = typeHandlersPackage;
    }

    public String getMapperLocations() {
        return mapperLocations;
    }

    public void setMapperLocations(String mapperLocations) {
        this.mapperLocations = mapperLocations;
    }
}
